/**
 * Dinos File System
 * @class
 */
var joFileManager = {

	/**
	 * 起動時に一度だけ実行される
	 * @private
	 */
	init: function(){
		var deferred = new Deferred();

//		this.storage = uu('Storage');
//			if(this.storage.toString() === 'MemStorage') this.storage = null;

		if(this.storage){
			this.fileTree = joCore.Node.textToDOM(this.storage.get('fileTree'));
		}else{
			return joCore.IO.read('disk.xml').
					next(function(req){
						joFileManager.fileTree = req.responseXML;
					});
		}
	},

	/**
	 * ファイルツリーを保存する
	 */
	_saveFileTree: function(){
//		var treeText = joCore.Node.DOMToText(this.fileTree);
//		location.href = 'data:application/octet-stream,' + encodeURIComponent(treeText);
	},
	
	/**
	 * パスをCSSに変換する
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {String} そのパスが指すフォルダを示すCSS	
	 */
	_pathToCSS: function(aPath){
		return aPath.replace('dinos:/', 'root')
					.replace(/\//g, '>')
					.replace(/>([^>]+)$/, '>file[name="$1"]')    //file name
					.replace(/(.[^>]*)>/g, 'folder[name="$1"]>')
					.replace(/>$/, '');
	},
	
	/**
	 * ファイルの名前を返す<br>
	 *   ファイルのパスを指定した場合： そのファイルの名前を返す<br>
	 *   フォルダのパスを指定した場合： 空文字を返す
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {String} ファイルの名前
	 */
	getFileNameFromPath: function(aPath){
		return aPath.match(/([^\/]*)$/)[1];
	},

	/**
	 * フォルダの名前を返す<br>
	 *   ファイルのパスを指定した場合： ファイルが入っているフォルダの名前を返す<br>
	 *   フォルダのパスを指定した場合： そのフォルダの名前を返す
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {String} フォルダの名前
	 */
	getFolderNameFromPath: function(aPath){
		return aPath.match(/([^\/]*)\/[^\/]*$/, '')[1] || 'Dinos';
	},

	/**
	 * 親フォルダのパスを返す
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {String/DinosPath} フォルダのパス
	 */
	getParentFolderFromPath: function(aPath){
		if(/\/$/.test(aPath)){
			//フォルダのとき
			return aPath.replace(/[^\/]*\/?$/, '');
		}else{
			//ファイルのとき
			return this.getParentFolderFromPath(aPath.replace(/[^\/]+$/, 'dammy/'));
		}	
	},

	/**
	 * 親フォルダのパスツリーを返す
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {Array} 親フォルダのパス群が入った配列
	 */
	getFolderTreeFromPath: function(aPath){
		var returnArray = [], aPath = aPath.replace(/[^\/]+$/, '');
		
		function getTree(path){
			returnArray.push(path);
			var parent = joFileManager.getParentFolderFromPath(path);
			if(parent.length > 8) getTree(parent); // dinos:// になったらやめる
		}

		getTree(aPath);
		
		return returnArray;
	},

	/**
	 * ファイルを取得する
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {Node} ファイルのノード
	 */
	getFile: function(aPath){
		var path = this._pathToCSS(aPath);
		joCore.logger.log('Get file:', path);
		var result = uuQuery(path, this.fileTree);
		return result.length ? result[0] : null;
	},

	/**
	 * ファイルを作成する<br>
	 * 指定した親フォルダがない場合は自動で作成する
	 *
	 * @param {String} aName 作成するファイルの名前
	 * @param {String/DinosPath} aPath 親フォルダのパス
	 * @param {Object} [aAttrs] ファイルに付加する属性
	 * @return {Node} 作成されたファイルのノード
	 */
	createFile: function(aName, aPath, aAttrs){
		var parent = this.getFile(aPath);
		if(!parent) parent = this.createFolder(aPath);
		
		if(aAttrs){
			aAttrs.name = aName;
			aAttrs.createdate = (new Date()).getTime();
		}
		
		var file = joCore.Node.createNode('file', aAttrs || { name: aName, createdate: (new Date()).getTime() }, '');
		parent.appendChild(file);

		this._saveFileTree();
		
		return file;
	},

	/**
	 * フォルダを作成する<br>
	 * 指定したフォルダが存在しない場合は自動で作成する
	 *
	 * @param {String/DinosPath} aPath 作成するフォルダのパス
	 * @return {Node} 作成したフォルダのノード
	 */
	createFolder: function(aPath){
		var folderTree = this.getFolderTreeFromPath(aPath);
		
		//存在する最も深いフォルダを調べる
		var deepestIndex = 0;
		folderTree.forEach(function(aFolder, aIndex, aArray){
			if(!joFileManager.exist(aFolder)) deepestIndex = aIndex;
		});
		deepestIndex++;

		var parent = this.getFile(folderTree[deepestIndex]);
		var folderName;
		for(var i=deepestIndex-1;i>=0;i--){
			folderName = this.getFolderNameFromPath(folderTree[i]);
			joCore.logger.log('Create Folder:', folderName);
			var node = joCore.Node.createNode('folder', { name: folderName, createdate: (new Date()).getTime() }, '');
			parent.appendChild(node);
			parent = node;
		}

		this._saveFileTree();
		
		return parent;
	},

	/**
	 * フォルダ/ファイルが存在するかどうか調べる
	 *
	 * @param {String/DinosPath} aPath パス
	 * @return {Boolean}
	 */
	exist: function(aPath){
		return this.getFile(aPath) ? true : false;
	},
	
	/**
	 * あるフォルダが指定したファイルを含んでいるかどうか調べる
	 *
	 * @param {String/DinosPath} aContainer 調べるフォルダ
	 * @param {String/DinosPath} aPath 調べるファイル
	 * @param {Boolean} isRecursive 子フォルダも対象にするかどうか
	 * @return {Boolean}
	 */
	isContain: function(aContainer, aPath, isRecursive){
		if(isRecursive){
			return aPath.indexOf(aContainer) !== -1;
		}else{
			return this.getParentFolderFromPath(aPath) === aContainer;
		}
	},

	/**
	 * ファイルに書き込む
	 *
	 * @param {String} aData 書き込むデータ
	 * @param {String/DinosPath} aPath 書き込み先のファイルのパス
	 * @return {Node} 書き込んだファイルのノード
	 */
	write: function(aData, aPath){
		var file = this.getFile(aPath);
		file.setAttribute('data', aData);

		this._saveFileTree();
		
		return file;
	},
	
	/**
	 * ファイルを移動する
	 *
	 * @param {String/DinosPath} aPath 移動するファイルのパス
	 * @param {String/DinosPath} moveTo 移動先のフォルダのパス
	 */
	move: function(aPath, moveTo){
		var file = this.getFile(aPath);
		var moveToFolder = this.getFile(moveTo);
		
		joCore.Node.moveNode(file, moveToFolder);
	},
	
	/**
	 * ファイルをリネームする
	 *
	 * @param {String/DinosPath} aPath リネームするファイル
	 * @param {String} newName リネーム後の名前
	 */
	rename: function(aPath, newName){
		var file = this.getFile(aPath);
		file.setAttribute('name', newName);
	},
	
	/**
	 * ファイルを削除する
	 *
	 * @param {String/DinosPath} aPath 削除するファイル
	 * @return {Boolean} 削除に成功したかどうか
	 */
	deleteFile: function(aPath){
		var file = this.getFile(aPath);
	
		if(!file) return false;
		
		try{
			file.parentNode.removeChild(file);
			return true;
		}catch(e){
			return false;
		}
	},
};


/**
 * File Picker
 * @constructor
 */
function joFilePicker(option){
	this.option = option || {};
	this.init();
}

joFilePicker.prototype = {

	init: function(){
	
	},
	
	
	show: function(){
		this.deferred = new Deferred();
		
		this.win = joCore.UI.window({
			width: 400,
			height: 350,
			application: 'System',
		});
		
		this['_build' + this.option.mode]();
		
		return this.deferred;
	},
	
	close: function(){
		this.win.close();
	},
	
	cancel: function(){
		this.close();
		this.deferred.call('');
	},
	
	_buildSave: function(){
		this.win.setTitle('Save As');
	
		//ファイル名入力欄
		this.win.addContent('<div class="filepicker-filename">Save As: <input type="text" class="filepicker-filename-input" /></div>');
	
		//ファイルツリー
		this.win.addContent('<div class="filepicker-filetree"></div>');
		
		//ボタン
		this.win.addContent('<div class="filepicker-controls">' + 
							'<button class="button-ok">Save</button>' + 
							'<button class="button-cancel">Cancel</button>' + 
							'</div>');
		
		joEvent.addEvent($C('button-ok', this.win.display.content), 'click', function(){
			var saveToPath = this.getSelectedFilePath()[0];
			var fileName = $C('filepicker-filename-input').value;
			
			//フォルダが選択されていない or ファイル名が入力されていない時は何もしない
			if(saveToPath.lastIndexOf('/') !== saveToPath.length-1 ||
			                     !fileName                           ) return;
			
			//ウィンドウを閉じる
			this.close();
			
			//処理を返す
			this.deferred.call(saveToPath + fileName);
		}, false, this);
		joEvent.addEvent($C('button-cancel', this.win.display.content), 'click', this.cancel, false, this);
		
		//ツリーの中身を構築する
		var fileTreeData = this._getFileTreeObject('dinos://');

		uki({
			view: 'uki.more.view.TreeList',
			rect: '400 400',
			anchors: 'left right top bottom',
			data: fileTreeData,
			rowHeight: 18,
			multiselect: false,
		}).attachTo($C('filepicker-filetree', this.win.display.content), '400 400');
	},
	
	_buildOpen: function(){
		this.win.setTitle('Open As');
	
		//ファイルツリー
		this.win.addContent('<div class="filepicker-filetree"></div>');
		
		//ボタン
		this.win.addContent('<div class="filepicker-controls">' + 
							'<button class="button-ok">Open</button>' + 
							'<button class="button-cancel">Cancel</button>' + 
							'</div>');
		
		joEvent.addEvent($C('button-ok', this.win.display.content), 'click', function(){
			var openToPath = this.getSelectedFilePath()[0];
			
			//フォルダが選択されている時は何もしない
			if(openToPath.lastIndexOf('/') === openToPath.length-1) return;
			
			//ウィンドウを閉じる
			this.close();
			
			//処理を返す
			this.deferred.call(openToPath);
		}, false, this);
		joEvent.addEvent($C('button-cancel', this.win.display.content), 'click', this.cancel, false, this);
		
		//ツリーの中身を構築する
		var fileTreeData = this._getFileTreeObject('dinos://');

		uki({
			view: 'uki.more.view.TreeList',
			rect: '400 400',
			anchors: 'left right top bottom',
			data: fileTreeData,
			rowHeight: 18,
			multiselect: false,
		}).attachTo($C('filepicker-filetree', this.win.display.content), '400 400');
	},


	/**
	 * Tree View用のファイルツリーオブジェクトを得る
	 * @param {String/DinosPath} root
	 */
	_getFileTreeObject: function(root){
		var parent = joFileManager.getFile(root);
		var children = parent.childNodes;
		var treeObject = [];
		
		for(var i=0,l=children.length;i<l;i++){
			var name = children[i].getAttribute('name');
			var item = {
				data: name,
				value: root + name + (children[i].hasChildNodes() ? '/' : '')
			};
			
			if(children[i].hasChildNodes())
				item.children = this._getFileTreeObject(root + name + '/');
			
			treeObject.push(item);
		}

		return treeObject;
	},
	
	/**
	 * 選択されたファイルのパスを返す
	 * @return {Array}
	 */
	getSelectedFilePath: function(){
		var paths = [];
		var selectedItems = uuQuery('div[class^=treeList-][class*=-selected]', this.win.display.content);
	
		paths = selectedItems.map(function(item){
			return item.firstChild.getAttribute('value');
		});
		
		return paths;
	},

};